package org.example.domain.order.service;


import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.example.domain.order.model.entity.OrderEntity;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;

import static org.example.types.common.MQConstants.LOCK_ORDER_PRODUCER_GROUP;
import static org.example.types.common.RedisConstants.SECKILL_RESULT_PREFIX;
import static org.example.types.common.RedisConstants.SECKILL_RESULT_TTL;

/**
 * @author yinghuashen
 * @version 1.0
 * @description:
 * @date 2025/3/9 21:13
 */

public interface IOrderService {

    String lockOrder(String userId, String productId, Integer count);

    String lockOrder_v2(OrderEntity orderEntity);

    /**
     * @author yinghuashen
     * @version 1.0
     * @description:
     * @date 2025/3/9 23:46
     */
    @Slf4j
    @Service
    @RocketMQTransactionListener(txProducerGroup = LOCK_ORDER_PRODUCER_GROUP)
    class LockOrderProducer implements RocketMQLocalTransactionListener {

        @Resource
        private StringRedisTemplate stringRedisTemplate;

        //lua脚本
        private static final DefaultRedisScript<Long> SECKILL_SCRIPT;

        static {
            SECKILL_SCRIPT = new DefaultRedisScript<>();
            SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));
            SECKILL_SCRIPT.setResultType(Long.class);
        }

        @Override
        public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object o) {
            try {
                if(!(o instanceof OrderEntity)){
                    return RocketMQLocalTransactionState.ROLLBACK;
                }

                OrderEntity order = (OrderEntity) o;
                // 执行lua脚本
                String userId = order.getUserId();
                String productId = order.getProductId();
                String orderId = order.getOrderId();
                Long result = stringRedisTemplate.execute(
                        SECKILL_SCRIPT,
                        Collections.emptyList(),
                        userId,
                        productId,
                        orderId,
                        SECKILL_RESULT_TTL
                );
                if(result == null){
                    return RocketMQLocalTransactionState.UNKNOWN;
                }

                switch (result.intValue()) {
                    case 0:
                        return RocketMQLocalTransactionState.COMMIT;
                    case 1:
                        log.info("库存不足, userId: {}, productId: {}", order.getUserId(), order.getProductId());
                        return RocketMQLocalTransactionState.ROLLBACK;
                    case 2:
                        log.info("重复下单, userId: {}, productId: {}", order.getUserId(), order.getProductId());
                        return RocketMQLocalTransactionState.ROLLBACK;
                    default:
                        log.warn("Lua 返回未知状态: {}", result);
                        return RocketMQLocalTransactionState.UNKNOWN;
                }

            } catch (Exception e) {
                log.error("执行lua脚本异常: ", e);
                return RocketMQLocalTransactionState.ROLLBACK;
            }
        }

        @Override
        public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
            try {
                Object payload = message.getPayload();
                if(!(payload instanceof OrderEntity)){
                    return RocketMQLocalTransactionState.ROLLBACK;
                }

                OrderEntity order = (OrderEntity) payload;
                String orderId = order.getOrderId();
                // 检查订单在缓存中是否存在
                String key = SECKILL_RESULT_PREFIX + orderId;
                Boolean result = stringRedisTemplate.hasKey(key);
                if(result == null){
                    return RocketMQLocalTransactionState.ROLLBACK;
                }else{
                    return RocketMQLocalTransactionState.COMMIT;
                }
            } catch (Exception e) {
                return RocketMQLocalTransactionState.ROLLBACK;
            }
        }
    }
}
